package navigation;

import config.*;
import java.util.*;

/**
 * Simple tester to try out different navigators
 *
 * @author hyurah
 */

public class NavigationTester {

	private static Navigator navi;
	private static Map map;
	private static int steps=0;
	private static List<PathPoint> objects=new ArrayList<PathPoint>();

	/**
	 * Runs the tester
	 *
	 * @param args not used
	 */

	public static void main(String[] args) {
		buildMap();
		try {
			drive();
		} catch(Exception e) {
			System.err.println(e);
		}
		System.out.print(navi.mapToString());
	}

	/**
	 * Drives through the maze
	 *
	 * @throws Exception when the map was incorrect or the navigator produced an error
	 */

	private static void drive() throws Exception{
		navi = Config.getSearchRedPointNavigator();
		boolean running=true, forward=false, right=false, backward=false, left=false;
		int deadEndDirection, direction;
		while(running) {
			direction=navi.decideDirection();
			if(direction<0) {
				running=false;
				System.out.println("Finish in " + steps + " Steps");
			} else {
				navi.directionChanged(direction);
				if(pointIsObject(navi.xPosition, navi.yPosition)) {
					navi.objectFound();
					System.out.print("Object found in Direction ");
					switch(direction) {
						case Direction.FORWARD: System.out.println("FORWARD"); break;
						case Direction.RIGHT: System.out.println("RIGHT"); break;
						case Direction.BACKWARD: System.out.println("BACKWARD"); break;
						case Direction.LEFT: System.out.println("LEFT"); break;
					}
					navi.directionChanged((4-direction)%4);
				} else {
					navi.moveOneStep();
					if(!navi.fieldIsKnown()) {
						if(map.getFieldDirectionState(navi.xPosition, navi.yPosition, (Direction.NORTH+navi.facingDirection)%4)==FieldDirectionState.PATH) {
							forward=true;
							deadEndDirection=Direction.FORWARD;
						} else forward=false;
						if(map.getFieldDirectionState(navi.xPosition, navi.yPosition, (Direction.EAST+navi.facingDirection)%4)==FieldDirectionState.PATH) {
							right=true;
							deadEndDirection=Direction.RIGHT;
						} else right=false;
						if(map.getFieldDirectionState(navi.xPosition, navi.yPosition, (Direction.SOUTH+navi.facingDirection)%4)==FieldDirectionState.PATH) {
							backward=true;
							deadEndDirection=Direction.BACKWARD;
						} else backward=false;
						if(map.getFieldDirectionState(navi.xPosition, navi.yPosition, (Direction.WEST+navi.facingDirection)%4)==FieldDirectionState.PATH) {
							left=true;
							deadEndDirection=Direction.LEFT;
						} else left=false;
						if(map.fieldIsDeadEnd(navi.xPosition, navi.yPosition)) navi.deadEndFound();
						else navi.addField(forward, right, backward, left);
						if(map.fieldIsRedPoint(navi.xPosition, navi.yPosition)) {
							navi.redPointFound();
							navi = Config.getGoToExitNavigator(navi);
							System.out.print("RedFound, ");
						}
					}
					switch(direction) {
						case Direction.FORWARD: System.out.print("FORWARD"); break;
						case Direction.RIGHT: System.out.print("RIGHT"); break;
						case Direction.BACKWARD: System.out.print("BACKWARD"); break;
						case Direction.LEFT: System.out.print("LEFT"); break;
					}
					System.out.print(", X:" + navi.xPosition + " Y:" + navi.yPosition);
					System.out.print(", " + forward + ", " + right + ", " + backward + ", " + left + "\n");
				}
				steps++;
			}
		}
	}

	/**
	 * Builds the maze
	 */

	private static void buildMap() {
		map = new Map();

		/*Killer-Maze*/
		/*map.deadEndFound(1, 0, Direction.SOUTH);
		map.addField(1, 1, true, false, true, false);
		map.addField(1, 2, true, true, true, false);
		map.addField(2, 2, false, true, false, true);
		map.addField(3, 2, false, true, true, true);
		map.addField(4, 2, false, true, true, true);
		map.addField(5, 2, false, true, true, true);
		map.addField(6, 2, false, false, true, true);
		map.addField(1, 3, true, false, true, false);
		map.deadEndFound(3, 3, Direction.NORTH);
		map.redPointFound(3, 3);
		map.addField(4, 3, true, true, false, false);
		map.addField(5, 3, true, false, false, true);
		map.addField(6, 3, true, false, true, false);
		map.addField(1, 4, true, false, true, false);
		map.addField(6, 4, true, false, true, false);
		map.addField(1, 5, true, true, false, false);
		map.addField(2, 5, false, true, false, true);
		map.addField(3, 5, false, true, false, true);
		map.addField(4, 5, false, true, false, true);
		map.addField(5, 5, false, true, false, true);
		map.addField(6, 5, true, false, false, true);*/

		/*Quali-Maze*/
		map.deadEndFound(1, 0, Direction.SOUTH);
		map.deadEndFound(4, 0, Direction.SOUTH);
		map.addField(1, 1, true, false, true, false);
		map.addField(2, 1, false, true, true, false);
		map.addField(3, 1, false, false, true, true);
		map.addField(4, 1, true, false, true, false);
		map.addField(1, 2, true, true, true, false);
		map.addField(2, 2, true, true, true, true);
		map.addField(3, 2, true, true, true, true);
		map.addField(4, 2, true, false, true, true);
		map.addField(1, 3, true, true, true, false);
		map.addField(2, 3, true, true, true, true);
		map.addField(3, 3, true, true, true, true);
		map.addField(4, 3, true, false, true, true);
		map.deadEndFound(1, 4, Direction.NORTH);
		map.addField(2, 4, true, false, true, false);
		map.addField(3, 4, true, false, true, false);
		map.deadEndFound(1, 4, Direction.NORTH);
		map.addField(1, 5, false, true, true, false);
		map.addField(2, 5, true, true, true, true);
		map.addField(3, 5, true, true, false, true);
		map.addField(4, 5, false, false, true, true);
		map.addField(1, 6, true, true, true, false);
		map.addField(2, 6, true, true, true, true);
		map.addField(3, 6, false, true, false, true);
		map.addField(4, 6, true, false, true, true);
		map.addField(1, 7, true, true, true, false);
		map.addField(2, 7, true, false, true, false);
		map.deadEndFound(3, 7, Direction.SOUTH);
		map.redPointFound(3, 7);
		map.addField(4, 7, true, false, true, false);
		map.addField(1, 8, true, true, false, false);
		map.addField(2, 8, true, true, true, true);
		map.addField(3, 8, true, true, false, true);
		map.addField(4, 8, true, false, false, true);
		map.deadEndFound(2, 9, Direction.NORTH);
		objects.add(new PathPoint(3, 3));
		objects.add(new PathPoint(2, 6));

		/* Object-Test-Maze */
		/*map.deadEndFound(1, 0, Direction.SOUTH);
		map.addField(1, 1, true, true, false, false);
		map.addField(2, 1, false, true, false, true);
		map.addField(3, 1, false, true, false, true);
		map.addField(4, 1, false, false, true, true);
		map.addField(1, 2, false, true, true, false);
		map.addField(2, 2, false, true, false, true);
		map.addField(3, 2, false, true, false, true);
		map.addField(4, 2, true, false, true, true);
		map.addField(1, 3, true, false, true, false);
		map.addField(4, 3, true, false, true, false);
		map.addField(1, 4, true, true, false, false);
		map.addField(2, 4, false, true, false, true);
		map.addField(3, 4, false, true, false, true);
		map.addField(4, 4, true, false, true, true);
		map.deadEndFound(4, 5, Direction.NORTH);
		map.redPointFound(4, 5);
		objects.add(new PathPoint(4, 3));*/

		/* Test-Maze */
		/*map.deadEndFound(1, 0, Direction.SOUTH);
		map.addField(1, 1, true, false, true, false);
		map.addField(2, 1, true, true, true, false);
		map.addField(1, 2, true, true, true, false);
		map.addField(2, 2, true, true, true, true);
		map.addField(1, 3, true, true, true, true);
		map.addField(2, 3, true, false, false, true);
		map.addField(1, 4, true, true, false, false);
		map.deadEndFound(2, 4, Direction.WEST);
		map.redPointFound(2, 4);
		//objects.add(new PathPoint(1, 2));*/

		/* Final-Maze */
		map.deadEndFound(1, 0, Direction.SOUTH);
		map.addField(1, 1, true, false, true, false);
		map.addField(2, 1, false, true, true, false);
		map.addField(3, 1, false, true, true, true);
		map.addField(4, 1, false, true, true, true);
		map.addField(5, 1, false, true, true, true);
		map.addField(6, 1, false, true, true, true);
		map.addField(7, 1, false, true, true, true);
		map.addField(8, 1, false, true, true, true);
		map.addField(9, 1, false, false, true, true);
		map.addField(10, 1, true, false, true, false);
		map.addField(1, 2, true, true, true, true);
		map.addField(2, 2, true, true, true, true);
		map.addField(3, 2, true, true, true, true);
		map.addField(4, 2, true, true, true, true);
		map.addField(5, 2, true, true, true, true);
		map.addField(6, 2, true, true, true, true);
		map.addField(7, 2, true, true, true, true);
		map.addField(8, 2, true, true, true, true);
		map.addField(9, 2, true, true, true, true);
		map.addField(10, 2, true, true, true, true);
		map.addField(1, 3, true, true, true, true);
		map.addField(2, 3, true, true, true, true);
		map.addField(3, 3, true, true, true, true);
		map.addField(4, 3, true, true, true, true);
		map.addField(5, 3, true, true, true, true);
		map.addField(6, 3, true, true, true, true);
		map.addField(7, 3, true, true, true, true);
		map.addField(8, 3, true, true, true, true);
		map.addField(9, 3, true, true, true, true);
		map.addField(10, 3, true, true, true, true);
		map.addField(1, 4, true, true, true, true);
		map.addField(2, 4, true, true, true, true);
		map.addField(3, 4, true, true, true, true);
		map.addField(4, 4, true, true, true, true);
		map.addField(5, 4, true, true, true, true);
		map.addField(6, 4, true, true, true, true);
		map.addField(7, 4, true, true, true, true);
		map.addField(8, 4, true, true, true, true);
		map.addField(9, 4, true, true, true, true);
		map.addField(10, 4, true, true, true, true);
		map.addField(1, 5, true, true, true, true);
		map.addField(2, 5, true, true, true, true);
		map.addField(3, 5, true, true, true, true);
		map.addField(4, 5, true, true, true, true);
		map.addField(5, 5, true, true, true, true);
		map.addField(6, 5, true, true, true, true);
		map.addField(7, 5, true, true, true, true);
		map.addField(8, 5, true, true, true, true);
		map.addField(9, 5, true, true, true, true);
		map.addField(10, 5, true, true, true, true);
		map.addField(1, 6, true, true, true, true);
		map.addField(2, 6, true, true, true, true);
		map.addField(3, 6, true, true, true, true);
		map.addField(4, 6, true, true, true, true);
		map.addField(5, 6, true, true, true, true);
		map.addField(6, 6, true, true, true, true);
		map.addField(7, 6, true, true, true, true);
		map.addField(8, 6, true, true, true, true);
		map.addField(9, 6, true, true, true, true);
		map.addField(10, 6, true, true, true, true);
		map.addField(1, 7, true, true, true, true);
		map.addField(2, 7, true, true, true, true);
		map.addField(3, 7, true, true, true, true);
		map.addField(4, 7, true, true, true, true);
		map.addField(5, 7, true, true, true, true);
		map.addField(6, 7, true, true, true, true);
		map.addField(7, 7, true, true, true, true);
		map.addField(8, 7, true, true, true, true);
		map.addField(9, 7, true, true, true, true);
		map.addField(10, 7, true, true, true, true);
		map.addField(1, 8, true, true, true, true);
		map.addField(2, 8, true, true, true, true);
		map.addField(3, 8, true, true, true, true);
		map.addField(4, 8, true, true, true, true);
		map.addField(5, 8, true, true, true, true);
		map.addField(6, 8, true, true, true, true);
		map.addField(7, 8, true, true, true, true);
		map.addField(8, 8, true, true, true, true);
		map.addField(9, 8, true, true, true, true);
		map.addField(10, 8, true, true, true, true);
		map.addField(1, 9, true, true, true, true);
		map.addField(2, 9, true, true, true, true);
		map.addField(3, 9, true, true, true, true);
		map.addField(4, 9, true, true, true, true);
		map.addField(5, 9, true, true, true, true);
		map.addField(6, 9, true, true, true, true);
		map.addField(7, 9, true, true, true, true);
		map.addField(8, 9, true, true, true, true);
		map.addField(9, 9, true, true, true, true);
		map.addField(10, 9, true, true, true, true);
		map.addField(1, 10, true, true, true, true);
		map.addField(2, 10, true, true, true, true);
		map.addField(3, 10, true, true, true, true);
		map.addField(4, 10, true, true, true, true);
		map.addField(5, 10, true, true, true, true);
		map.addField(6, 10, true, true, true, true);
		map.addField(7, 10, true, true, true, true);
		map.addField(8, 10, true, true, true, true);
		map.addField(9, 10, true, true, true, true);
		map.addField(10, 10, true, true, true, true);
		map.addField(1, 11, true, true, true, true);
		map.addField(2, 11, true, true, true, true);
		map.addField(3, 11, true, true, true, true);
		map.addField(4, 11, true, true, true, true);
		map.addField(5, 11, true, true, true, true);
		map.addField(6, 11, true, true, true, true);
		map.addField(7, 11, true, true, true, true);
		map.addField(8, 11, true, true, true, true);
		map.addField(9, 11, true, true, true, true);
		map.addField(10, 11, true, true, true, true);
		map.addField(1, 12, true, true, true, true);
		map.addField(2, 12, true, true, true, true);
		map.addField(3, 12, true, true, true, true);
		map.addField(4, 12, true, true, true, true);
		map.addField(5, 12, true, true, true, true);
		map.addField(6, 12, true, true, true, true);
		map.addField(7, 12, true, true, true, true);
		map.addField(8, 12, true, true, true, true);
		map.addField(9, 12, true, true, true, true);
		map.addField(10, 12, true, true, true, true);

		//System.out.println(map.toString());
	}

	/**
	 * Checks if an object is located at the specified position
	 *
	 * @param x x position of the object
	 * @param y y position of the object
	 * @return true if object is found
	 */

	private static boolean pointIsObject(int x, int y) {
		boolean result = false;
		switch(navi.facingDirection) {
			case Direction.NORTH: y--; break;
			case Direction.EAST: x++; break;
			case Direction.SOUTH: y++; break;
			case Direction.WEST: x--; break;
		}
		for(int i=0; i<objects.size(); i++) {
			if(x==objects.get(i).getX() && y==objects.get(i).getY()) {
				result = true;
			}
		}
		return result;
	}

}
